/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.webos.java.passwords;

import java.sql.PreparedStatement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import org.json.JSONObject;
import org.webos.java.base.Dialog;
import org.webos.java.base.DialogType;
import org.webos.java.base.NetworkManager;
import org.webos.java.base.RemoteMessage;
import org.webos.java.base.dialog.QuestionDialog;
import org.webos.java.base.dialog.QuestionResponse;
import org.webos.java.base.utils.CryptoUtil;
import org.webos.java.root.Log;

/**
 *
 * @author Kostya
 */
@DialogType(jsClass="passwords.EntryEditor")
public class EntryEditor extends Dialog<PasswordManager>{

    PasswordItem passwordItem = null;
    boolean passHidden = false;
    String login = "";
    String pass1 = "";
    String pass2 = "";
    static String letters = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm";
    static String numbers = "0123456789";
    static String symbols = "~!?,.@#$%^&*(){}[]-+=_/\\";

    EntryEditor(PasswordManager aManager, PasswordItem aPasswordItem) {
        super(aManager);
        passwordItem = aPasswordItem;
        try {
            JSONObject settings = new JSONObject(aManager.getOption("options", "{}"));
            if(passwordItem!=null){
                getData().putOpt("edit", true);
                getData().putOpt("name", passwordItem.name);
                getData().putOpt("url", passwordItem.url);
                getData().putOpt("notes", passwordItem.notes);
                String masterPassword = getApplication().getPassword();
                if(masterPassword==null){
                    return;
                }
                login = CryptoUtil.decode(masterPassword, aPasswordItem.login);//Decode
                pass1 = CryptoUtil.decode(masterPassword, aPasswordItem.password);
                pass2 = pass1;
//                getData().putOpt("login", passwordItem.login);
            }
            getData().putOpt("login", login);
            getData().putOpt("password1", pass1);
            getData().putOpt("password2", pass2);
            getData().put("pass_hidden", passHidden);
            getData().putOpt("use_letters", settings.optBoolean("use_letters", true));
            getData().putOpt("use_numbers", settings.optBoolean("use_numbers", true));
            getData().putOpt("use_symbols", settings.optBoolean("use_symbols", false));
            getData().putOpt("pass_length", settings.optInt("pass_length", 16));
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
        show();
    }

    @RemoteMessage
    public JSONObject showPassword(JSONObject aData){
        try {
            if(passHidden){
                aData.putOpt("password1", pass1);
                aData.putOpt("password2", pass2);
                aData.putOpt("login", login);
            }else{
                login = aData.optString("login", "");
                pass1 = aData.optString("password1", "");
                pass2 = aData.optString("password2", "");
            }
            passHidden = !passHidden;
            aData.putOpt("pass_hidden", passHidden);
//            Log.debug(this, "ShowPassword: "+aData);
            return aData;
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
        return NetworkManager.getErrorObject(1006, "Can't execute operation");
    }

    @RemoteMessage
    public JSONObject generatePassword(JSONObject aData){
        try {
            Random random = new Random(new Date().getTime());
            int passLength = aData.optInt("pass_length", 0);
            List<String> areas = new ArrayList<String>();
            if(aData.optBoolean("use_letters"))
                areas.add(letters);
            if(aData.optBoolean("use_numbers"))
                areas.add(numbers);
            if(aData.optBoolean("use_symbols"))
                areas.add(symbols);
            if(areas.size()==0){
                areas.add(letters);
                areas.add(numbers);
                areas.add(symbols);
            }
            char[] password = new char[passLength];
            for (int i = 0; i < password.length; i++) {
                int areaIndex = random.nextInt(areas.size());
                String area = areas.get(areaIndex);
                int charIndex = random.nextInt(area.length());
                password[i] = area.charAt(charIndex);
            }
            aData.putOpt("password", new String(password));
            return aData;
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
        return NetworkManager.getErrorObject(1005, "Can't generate password");
    }

    @RemoteMessage
    public JSONObject okClick(JSONObject aData){
        try {
            if(!passHidden){
                login = aData.optString("login", "");
                pass1 = aData.optString("password1", "");
                pass2 = aData.optString("password2", "");
            }
            String name = aData.optString("name", "");
            String url = aData.optString("url", "");
            String notes = aData.optString("notes", "");
            if("".equals(name) && "".equals(url)){
                return NetworkManager.getErrorObject(1010, "Name or URL should be provided");
            }
            if(!pass1.equals(pass2)){
                return NetworkManager.getErrorObject(1011, "Passwords doesn't match");
            }
            String masterPassword = getApplication().getPassword();
            if(masterPassword==null){
                //continue editing
                return null;
            }
            //Saving everything to DB
            PreparedStatement st = null;
            String encodedLogin = CryptoUtil.encode(masterPassword, login);
            String encodedPass = CryptoUtil.encode(masterPassword, pass1);
            if(passwordItem!=null){
                passwordItem.name = name;
                passwordItem.url = url;
                passwordItem.notes = notes;
                passwordItem.login = encodedLogin;
                passwordItem.password = encodedPass;
                st = getApplication().connection.prepareQuery("update PASSWORDS " +
                        "set name=?, username=?, password=?, url=?, notes=? where id=?");
                st.setString(1, name);
                st.setString(2, encodedLogin);
                st.setString(3, encodedPass);
                st.setString(4, url);
                st.setString(5, notes);
                st.setInt(6, passwordItem.id);
                st.execute();
            }else{
                if(getApplication().grid.categorieItem==null){
                    return NetworkManager.getErrorObject(1012, "Folder not selected");
                }
                st = getApplication().connection.prepareQuery("insert into PASSWORDS " +
                        "(name, username, password, id_cat, create_date, url, notes) values " +
                        "(?, ?, ?, ?, ?, ?, ?)");
                st.setString(1, name);
                st.setString(2, encodedLogin);
                st.setString(3, encodedPass);
                st.setInt(4, getApplication().grid.categorieItem.id);
                st.setTimestamp(5, new Timestamp(new Date().getTime()));
                st.setString(6, url);
                st.setString(7, notes);
                st.execute();
                passwordItem = new PasswordItem(getApplication().grid.controller,
                        getApplication().connection.getLastID(), name,
                        encodedLogin,
                        encodedPass, url, notes);
            }
            getApplication().connection.commit();
            closeDialog(aData);
            getApplication().grid.controller.appendItem(passwordItem);
            getApplication().grid.controller.setSelected(passwordItem);

            JSONObject settings = new JSONObject(getApplication().getOption("options", "{}"));
            settings.putOpt("use_letters", aData.optBoolean("use_letters"));
            settings.putOpt("use_numbers", aData.optBoolean("use_numbers"));
            settings.putOpt("use_symbols", aData.optBoolean("use_symbols"));
            settings.putOpt("pass_length", aData.optInt("pass_length", 16));
            getApplication().setOption("options", settings.toString());
            return null;
        } catch (Throwable t) {
            getApplication().connection.rollback();
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
        return NetworkManager.getErrorObject(1014, "Can't save entry to database");
    }

    @RemoteMessage
    public JSONObject removeClick(JSONObject aData){
        try {
            int aResponse = new QuestionDialog(getApplication(),
                    "You sure want to remove password?").ask();
            if(aResponse!=0)
                return null;
            PreparedStatement st = getApplication().connection.
                    prepareQuery("delete from PASSWORDS where id=?");
            st.setInt(1, passwordItem.id);
            st.execute();
            getApplication().connection.commit();
            getApplication().grid.controller.removeItem(passwordItem);
            closeDialog(null);
            return null;
        } catch (Throwable t) {
            Log.error(this, "Exception thrown: " + t.getMessage());
            t.printStackTrace();
        }
        return NetworkManager.getErrorObject(1014, "Can't remove password");
    }

}
